package com.heima.wemedia.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.heima.client.article.IArticleClient;
import com.heima.common.exception.CustomException;
import com.heima.common.redis.CacheService;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.common.pojos.wemedia.WmSensitive;
import com.heima.model.common.pojos.wemedia.WmUser;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmCommentMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.receive.dtos.*;
import com.heima.wemedia.receive.pojos.*;
import com.heima.wemedia.receive.vo.ApCommentAndRepayVo;
import com.heima.wemedia.receive.vo.CommentVo;
import com.heima.wemedia.service.BaiduScanService;
import com.heima.wemedia.service.WmCommentService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class WmCommentServiceImpl implements WmCommentService {
    @Autowired
    private WmCommentMapper wmCommentMapper;
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private CacheService cacheService;
    @Autowired
    private WmSensitiveMapper wmSensitiveMapper;
    @Autowired
    private BaiduScanService baiduScanService;
    @Autowired
    private IArticleClient articleClient;
    @Autowired
    private WmUserMapper wmUserMapper;

    /**
     * 查询评论分页
     *
     * @param commentDto
     * @return {@link Page }<{@link CommentVo }>
     */
    public Page<CommentVo> findNewsComments(CommentPageDto commentDto) {
        //校验参数
        if (commentDto == null) {
            throw new CustomException(AppHttpCodeEnum.PARAM_REQUIRE);
        }
        //如果前端没有给每页查询条数则设置默认值
        commentDto.checkParam();
        //1.根据当前用户id查询wm_news
        //1.1获取用户id
        Integer userId = WmThreadLocalUtil.get();
        //1.2构建分页
        Page<CommentVo> commentVoPage = new Page<>(commentDto.getPage(), commentDto.getSize());

        LocalDateTime benginTime = LocalDateTime.ofInstant(commentDto.getBeginDate().toInstant(), ZoneId.systemDefault());
        LocalDateTime endTime = LocalDateTime.ofInstant(commentDto.getEndDate().toInstant(), ZoneId.systemDefault());
        if (benginTime.equals(endTime)) {
            endTime = endTime.minusDays(-1);
        }
        IPage<Comment> list = wmCommentMapper.selectCommentList(commentVoPage, benginTime, endTime, userId);
        List<CommentVo> commentVos = new ArrayList<>();
        for (Comment comment : list.getRecords()) {
            CommentVo commentVo = new CommentVo();
            commentVo.setId(comment.getArticleId());
            commentVo.setTitle(comment.getTitle());
            //查询出当前文章的所有评论
            List<ApComment> apCommentList = mongoTemplate.find(Query.query(Criteria.where("entryId")
                            .is(comment.getArticleId())),
                    ApComment.class);
            //如果没有查到评论则直接返回0条评论
            if (CollectionUtils.isEmpty(apCommentList)) {
                commentVo.setComments(0);
            } else {
                //查询ap_comment_repay表查询出当前文章所有评论的评论
                for (ApComment repay : apCommentList) {
                    List<ApCommentRepay> repayList = mongoTemplate.find(Query.query(Criteria
                            .where("commentId").is(repay.getId())
                    ), ApCommentRepay.class);
                    //查询到的文章评论加上文章评论的评论则是文章的总评论
                    Integer len = apCommentList.size() + repayList.size();
                    commentVo.setComments(len);
                }
            }
            commentVo.setIsComment(comment.getIsComment());
            commentVo.setCreatedTime(comment.getCreatedTime());
            commentVos.add(commentVo);
        }
        commentVoPage.setRecords(commentVos);
        return commentVoPage;
    }


    /**
     * 作者回复评论
     *
     * @param commentRepayDto commentId 评论id content 评论内容
     * @return
     */
    @Override
    public ResponseResult replyComment(CommentRepayDto commentRepayDto) {
        //数据校验
        if (ObjectUtils.isEmpty(commentRepayDto) || commentRepayDto.getCommentId() == null || StringUtils.isEmpty(commentRepayDto.getContent()))
            return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
            //查看评论内容是否大于140字
        if (commentRepayDto.getContent().length() > 140)
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_LENGTH_ERROR);
        //从线程拿取作者id，是否存在
        Integer authorId = WmThreadLocalUtil.get();
        if (authorId == null) return ResponseResult.errorResult(AppHttpCodeEnum.NEED_LOGIN);
        //根据id拿取作者信息
        WmUser wmUser = wmUserMapper.selectById(authorId);
        //根据评论id查询评论是否存在
        ApComment apComment = mongoTemplate.findOne(Query.query(Criteria.where("id").is(commentRepayDto.getCommentId())), ApComment.class);
        if (ObjectUtils.isEmpty(apComment)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        //评论内容审核
        if (!scanText(commentRepayDto.getContent())) {
            return ResponseResult.errorResult(AppHttpCodeEnum.COMMENT_ERROR);
        }
        //填充数据
        ApCommentRepay apCommentRepay = new ApCommentRepay();
        apCommentRepay.setCommentId(String.valueOf(commentRepayDto.getCommentId()));
        apCommentRepay.setContent(commentRepayDto.getContent());
        apCommentRepay.setAuthorId(wmUser.getId());
        apCommentRepay.setAuthorName(wmUser.getName());
        apCommentRepay.setLikes(0);
        apCommentRepay.setCreatedTime(new Date());
        apCommentRepay.setUpdatedTime(new Date());
        //给mongoDB里的评论的回复数加一
        Integer reply = apComment.getReply();
        apComment.setReply(reply + 1);
        mongoTemplate.save(apComment);
        //将作者文章回复存入mongoDB
        mongoTemplate.save(apCommentRepay);
        //返回成功
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 查看回复评论列表
     *
     * @param cPInfoDto
     * @return
     */
    @Override
    public ResponseResult findReplyComments(CommentPageInfoDto cPInfoDto) {
        //1.数据校验
        if (cPInfoDto.getArticleId() == null) return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        cPInfoDto.checkParam();

        //2.分页查询数据
        //排序规则，按照创建时间倒排
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        //分页
        PageRequest pageRequest = PageRequest.of(cPInfoDto.getPage() - 1, cPInfoDto.getSize());
        //2.1用户评论查询
        List<ApComment2> apCommentList = mongoTemplate.find(Query.query(Criteria.where("entryId").is(cPInfoDto.getArticleId())).with(pageRequest).with(sort), ApComment2.class);
        //2.2评论回复查询
        List<ApCommentAndRepayVo> apComments = new ArrayList<>();
        for (ApComment2 apComment : apCommentList) {
            String commentId = apComment.getId();
            List<ApCommentRepay> apCommentRepays = mongoTemplate.find(Query.query(Criteria.where("commentId").is(commentId))
                            .with(sort)
                    , ApCommentRepay.class);
            //数据填充进apComments
            ApCommentAndRepayVo apC = new ApCommentAndRepayVo();
            apC.setApComments(apComment);
            apC.setApCommentRepays(apCommentRepays);
            apComments.add(apC);
        }
        return ResponseResult.okResult(apComments);
    }

    /**
     * 删除评论
     *
     * @param commentId
     * @return
     */
    @Override
    public ResponseResult delComment(String commentId) {
        //数据校验
        if (StringUtils.isEmpty(commentId)) return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        //查询评论
        ApComment apComment = mongoTemplate.findOne(Query.query(Criteria.where("id").is(commentId)), ApComment.class);
        if (ObjectUtils.isEmpty(apComment)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        //删除评论
        mongoTemplate.remove(apComment);
        //删除评论点赞
        mongoTemplate.remove(Query.query(Criteria.where("commentId").is(commentId)), ApCommentLike.class);
        //删除回复评论
        mongoTemplate.remove(Query.query(Criteria.where("commentId").is(commentId)), ApCommentRepay.class);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    /**
     * 删除评论回复
     *
     * @param commentRepayId
     * @return
     */
    @Override
    public ResponseResult delCommentRepay(String commentRepayId) {
        //数据校验
        if (StringUtils.isEmpty(commentRepayId)) return ResponseResult.errorResult(AppHttpCodeEnum.PARAM_REQUIRE);
        //查询回复评论
        ApCommentRepay apCommentRepay = mongoTemplate.findOne(Query.query(Criteria.where("id").is(commentRepayId)), ApCommentRepay.class);
        if (ObjectUtils.isEmpty(apCommentRepay)) return ResponseResult.errorResult(AppHttpCodeEnum.DATA_NOT_EXIST);
        //删除回复评论
        mongoTemplate.remove(apCommentRepay);
        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }


    //审核评论内容
    private boolean scanText(String text) {
        //1. 先内审：走自定义敏感词库过滤
        //1.1 加载系统敏感词数据
        //缓存优化：先查缓存，缓存有：直接用，缓存没有：再查数据库，并将查到的数据添加到缓存
        List<String> sensitiveList = JSONArray.parseArray(cacheService.get("sensitives"), String.class);
        //缓存没有：再查数据库
        if (sensitiveList == null) {
            List<WmSensitive> wmSensitives = wmSensitiveMapper.selectList(null);
            sensitiveList = wmSensitives.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
            //添加到缓存
            cacheService.set("sensitives", JSON.toJSONString(sensitiveList));
        }
        //1.2 初始化DFA算法字典
        SensitiveWordUtil.initMap(sensitiveList);
        //1.3 调用DFA算法进行指定文本的敏感词过滤
        Map<String, Integer> resMap = SensitiveWordUtil.matchWords(text);
        if (resMap != null && resMap.size() > 0) {
            return false;
        }
        //2. 再外审：走第三方文本审核接口：百度云API
        Integer conclusionType = baiduScanService.scanText(text);
        if (conclusionType == 2) {
            return false;
        } else if (conclusionType == 3 || conclusionType == 4) {
            return false;
        }
        return true;
    }


    /**
     * 打开或关闭评论
     *
     * @param updateIsCommentDto
     */
    @Override
    public void updateCommentStatus(UpdateIsCommentDto updateIsCommentDto) {
        //先通过远程调用修改ap_article_cinfig中的is_comment
        articleClient.updateIsCommentStatus(Long.valueOf(updateIsCommentDto.getArticleId()), updateIsCommentDto.getOperation());
        //删除MongoDB中的三张表的评论
        if (updateIsCommentDto.getOperation() == 0) {
            //先根据文章id查询对应的评论id
            List<ApComment> commentIdList = mongoTemplate.find(Query.query(Criteria.where("entryId")
                            .is(Long.valueOf(updateIsCommentDto.getArticleId()))),
                    ApComment.class);

            for (ApComment apComment : commentIdList) {
                //先删除ap_comment_like表
                mongoTemplate.remove(Query.query(Criteria.where("commentId")
                                .is(apComment.getId())),
                        ApCommentLike.class);
                //在删除ap_comment_repay
                mongoTemplate.remove(Query.query(Criteria.where("commentId")
                                .is(apComment.getId())),
                        ApCommentRepay.class);
                mongoTemplate.remove(apComment);
                mongoTemplate.remove(Query.query(Criteria.where("commentId").is(apComment.getId())), ApCommentRepay.class);
                mongoTemplate.remove(apComment);
            }

            //todo::清空ap_article表中的评论数量 ----------远程调用
            articleClient.deleteAllComment(Long.valueOf(updateIsCommentDto.getArticleId()));
        }
    }


    /**
     * 评论点赞
     *
     * @param likesDto
     * @return {@link Integer }
     */
    @Override
    public Long updateCommentLike(CommentLikeDto likesDto) {
        String commentId = likesDto.getCommentId();
        //获取当前作者ID
        Integer userId = WmThreadLocalUtil.get();
        //根据评论ID查询当前评论信息
        ApComment apComment = mongoTemplate.findOne(
                Query.query(Criteria.where("id")
                        .is(commentId)),
                ApComment.class
        );
        //校验当然评论是否存在
        if (ObjectUtils.isEmpty(apComment)) {
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        if (likesDto.getOperation() == Integer.valueOf(Comment.NumberConstants.ZERO.getValue())) {
            //1.1修改当前评论的like字段+1
            apComment.setLikes(apComment.getLikes() + 1);
            mongoTemplate.updateFirst(
                    Query.query(Criteria.where("id")
                            .is(commentId)),
                    new Update()
                            .set("likes", apComment.getLikes()),
                    ApComment.class);
            //1.2将作者信息保存到ap_comment_like中
            ApCommentLike apCommentLike = new ApCommentLike();
            apCommentLike.setAuthorId(userId);
            apCommentLike.setCommentId(apComment.getId());
            mongoTemplate.save(apCommentLike);

        } else {
            //2取消点赞
            //2取消点赞
            long tmp = apComment.getLikes() - 1;
            tmp = tmp < 1 ? 0 : tmp;
            apComment.setLikes(tmp);
            mongoTemplate.save(apComment);
            //删除ap_comment_like表中的数据
            mongoTemplate.remove(Query.query(
                            Criteria.where("commentId")
                                    .is(apComment.getId())),
                    ApCommentLike.class);
        }
        return apComment.getLikes();
    }
}
